﻿using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using Turquoise.Business.Abstract;
using Turquoise.Core.Entities;
using Turquoise.DataAccess.Abstract;
using Turquoise.Entities.Complex.UserModels;
using Turquoise.Entities.Data;
using Turquoise.Exceptions;
using Turquoise.Globalization;
using Turquoise.Helpers;
using Turquoise.Services.Messaging.Options;
using Turquoise.Validation.FluentValidation.UserValidation;

namespace Turquoise.Business
{
    public class UserManager : IUserService
    {
        private readonly IRepository<User> _repositoryUser;
        private readonly IRepository<UserGroup> _repositoryUserGroup;
        private readonly IRepository<UserGroupUserLine> _repositoryUserGroupUserLine;
        private readonly IRepository<UserHistory> _repositoryUserHistory;
        private readonly ISettingService _settingService;
        private readonly IEmailService _emailService;
        private readonly ILanguageService _languageService;

        public UserManager(IRepository<User> repositoryUser, ISettingService settingService, ILanguageService languageService, IEmailService emailService, IRepository<UserGroup> repositoryUserGroup, IRepository<UserGroupUserLine> repositoryUserGroupUserLine, IRepository<UserHistory> repositoryUserHistory)
        {
            _repositoryUser = repositoryUser;
            _settingService = settingService;
            _languageService = languageService;
            _emailService = emailService;
            _repositoryUserGroup = repositoryUserGroup;
            _repositoryUserGroupUserLine = repositoryUserGroupUserLine;
            _repositoryUserHistory = repositoryUserHistory;
        }

        public UpdateModel ForgotPassword()
        {
            return new UpdateModel
            {
                Languages = _languageService.GetAll()
            };
        }

        public void ForgotPassword(UpdateModel model)
        {
            var validator = new ForgotPasswordValidator(model);
            model.User = new User
            {
                Email = model.Email
            };
            var validationResults = validator.Validate();
            if (!validator.IsValid)
            {
                throw new ValidationException(Resources.InvalidEntityMessage)
                {
                    ValidationResult = validationResults
                };
            }
            var user = _repositoryUser.Get(e => e.Email == model.Email);
            if (user == null)
            {
                throw new NotFoundException(Resources.NotFound);
            }
            var newPassword = SecurityHelper.CreatePassword(8);
            user.Password = newPassword.ToSha512();
           var affectedUser = _repositoryUser.Update(user);
            affectedUser.Password = newPassword;
            var emailTemplatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"ApplicationFiles\\EmailTemplates\\ForgotPassword.{model.SelectedLanguageCode}.html");
            _emailService.Send(affectedUser, emailTemplatePath, TypeOptions.ForgotPassword);

        }

        public AddModel SignUp()
        {
            return new AddModel
            {
                User = new User(),
                Languages = _languageService.GetAll()
            };
        }

        public void SignUp(AddModel model)
        {
            var validator = new AddValidator(model);
            var user = model.User;
            var validationResults = validator.Validate();
            if (!validator.IsValid)
            {
                throw new ValidationException(Resources.InvalidEntityMessage)
                {
                    ValidationResult = validationResults
                };
            }

            if (_repositoryUser.Get(e=>e.Username==user.Username) != null)
            {
                throw new DuplicateException(Resources.UsernameNotDuplicated);
            }
            if (_repositoryUser.Get(e => e.Email == user.Email) != null)
            {
                throw new DuplicateException(string.Format(Resources.EmailNotDuplicated));
            }
            var selectedLanguage = model.Languages.Find(m => m.LanguageCode == model.SelectedLanguageCode);

            user.LanguageId = selectedLanguage.Id;
            var password = user.Password;
            user.Password = user.Password.ToSha512();
            user.CreateDate = DateTime.Now;
            user.CreatedBy = 1;
            user.UpdateDate = DateTime.Now;
            user.UpdatedBy = 1;
            var affectedUser = _repositoryUser.Add(user);
            user.CreatedBy = affectedUser.Id;
            user.UpdatedBy = affectedUser.Id;
            user.DisplayOrder = affectedUser.Id;
            affectedUser = _repositoryUser.Update(user);

            var userGroup = _repositoryUserGroup.Get(e => e.Id == 1);
            if (userGroup != null)
            {
                var userGroupUserLine = new UserGroupUserLine
                {
                    UserId = affectedUser.Id,
                    CreateDate = DateTime.Now,
                    CreatedBy = affectedUser.CreatedBy,
                    UpdateDate = DateTime.Now,
                    UpdatedBy = affectedUser.UpdatedBy,
                    UserGroupId = userGroup.Id
                };
                _repositoryUserGroupUserLine.Add(userGroupUserLine);
            }

            var userFilesName = ConfigurationHelper.GetAppSetting("UserFiles");
            var userDirectoryPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, userFilesName + "\\" + affectedUser.Email.ToMd5());

            if (!Directory.Exists(userDirectoryPath))
            {
                var publicUserFiles = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, userFilesName + "\\Public");
                Directory.CreateDirectory(userDirectoryPath);
                FileHelper.CopyDirectory(publicUserFiles, userDirectoryPath);
            }

            affectedUser.Password = password;

            

            var emailTemplatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"ApplicationFiles\\EmailTemplates\\SignUp.{model.SelectedLanguageCode}.html");
            _emailService.Send(affectedUser, emailTemplatePath, TypeOptions.Activation);
        }

        public UpdateModel UpdateMyPassword()
        {
            var identity = (TurquoiseIdentity)Thread.CurrentPrincipal.Identity;
            return new UpdateModel
            {
                User =  _repositoryUser.Get(e=>e.Id==identity.UserId)
            };
        }

        public void UpdateMyPassword(UpdateModel model)
        {
            var validator = new UpdatePasswordValidator(model);
            var validationResults = validator.Validate();
            if (!validator.IsValid)
            {
                throw new ValidationException(Resources.InvalidEntityMessage)
                {
                    ValidationResult = validationResults
                };
            }
            var identity = (TurquoiseIdentity)Thread.CurrentPrincipal.Identity;
            var user = _repositoryUser.Get(e => e.Id == identity.UserId);
            if (model.User.OldPassword.ToSha512() != user.Password)
            {
                throw new NotFoundException(Resources.OldPasswordInvalid);
            }
            var userHistory = new UserHistory
            {
                UserId = user.Id,
                Username = user.Username,
                Password = user.Password,
                Email = user.Email,
                FirstName = user.FirstName,
                LastName = user.LastName,
                LanguageId = user.LanguageId,
                CreateDate = user.CreateDate,
                CreatedBy = user.CreatedBy,
                UpdateDate = user.UpdateDate,
                UpdatedBy = user.UpdatedBy,
                DisplayOrder = user.DisplayOrder,
                IsApproved = user.IsApproved,
                IsDeleted = false
            };
            _repositoryUserHistory.Add(userHistory);
            var password = model.User.Password;
            user.Password = password.ToSha512();
            user.UpdateDate = DateTime.Now;
            user.UpdatedBy = user.Id;
            model.User = user;
            var affectedUser = _repositoryUser.Update(user);
            affectedUser.Password = password;

            

            var emailTemplatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"ApplicationFiles\\EmailTemplates\\UpdateMyPassword.{identity.LanguageCode}.html");
            _emailService.Send(affectedUser, emailTemplatePath, TypeOptions.UpdatePassword);
        }

        public UpdateModel UpdateMyInformation()
        {
            var identity = (TurquoiseIdentity)Thread.CurrentPrincipal.Identity;
            return new UpdateModel
            {
                User = _repositoryUser.Get(e => e.Id == identity.UserId),
                Languages = _languageService.GetAll(),
                SelectedLanguageCode =  identity.LanguageCode
            }; 
        }

        public void UpdateMyInformation(UpdateModel model)
        {
           
            var identity = (TurquoiseIdentity)Thread.CurrentPrincipal.Identity;
            var validator = new UpdateValidator(model);
            var modelUser = model.User;
            modelUser.Password = identity.Password;
            var validationResults = validator.Validate();
            if (!validator.IsValid)
            {
                throw new ValidationException(Resources.InvalidEntityMessage)
                {
                    ValidationResult = validationResults
                };
            }

            var user = _repositoryUser.Get(e => e.Id == identity.UserId);
            if (modelUser.Username != user.Username)
            {
                if (_repositoryUser.GetList().Any(p => p.Username == modelUser.Username))
                {
                    throw new DuplicateException(Resources.UsernameNotDuplicated);
                }
            }

            if (modelUser.Email != user.Email)
            {
                if (_repositoryUser.GetList().Any(p => p.Email == modelUser.Email))
                {
                    throw new DuplicateException(Resources.EmailNotDuplicated);
                }
            }

            var userHistory = new UserHistory
            {
                UserId = user.Id,
                Username = user.Username,
                Password = user.Password,
                Email = user.Email,
                FirstName = user.FirstName,
                LastName = user.LastName,
                LanguageId = user.LanguageId,
                CreateDate = user.CreateDate,
                CreatedBy = user.CreatedBy,
                UpdateDate = user.UpdateDate,
                UpdatedBy = user.UpdatedBy,
                DisplayOrder = user.DisplayOrder,
                IsApproved = user.IsApproved,
                IsDeleted = false
            };

            _repositoryUserHistory.Add(userHistory);
            user.Username = modelUser.Username;
            user.Email = modelUser.Email;
            user.FirstName = modelUser.FirstName;
            user.LastName = modelUser.LastName;
            var selectedLanguage = model.Languages.Find(m => m.LanguageCode == model.SelectedLanguageCode);
            user.LanguageId = selectedLanguage.Id;
            user.UpdateDate = DateTime.Now;
            user.UpdatedBy = identity.UserId;
            var affectedUser = _repositoryUser.Update(user);
            identity.LanguageCode = selectedLanguage.LanguageCode;

            model.User = affectedUser;
            var principal = new TurquoisePrincipal(identity);
            Thread.CurrentPrincipal = principal;
            Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(identity.LanguageCode);
            Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(identity.LanguageCode);
            var emailTemplatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"ApplicationFiles\\EmailTemplates\\UpdateUserInformation.{identity.LanguageCode}.html");
            _emailService.Send(affectedUser, emailTemplatePath, TypeOptions.Update);
        }


        public DetailModel MyAccount()
        {
            var identity = (TurquoiseIdentity)Thread.CurrentPrincipal.Identity;
            var user = _repositoryUser.Get(e=>e.Id== identity.UserId);
            var lastLoginTime = DateTime.Now.ToString("G");
            var sessionHistories = user.SessionHistories;
            var remainingSessionTime = _settingService.GetValueByKey("SessionTimeOut");

            if (sessionHistories.Count <= 0)
            {
                return new DetailModel
                {
                    User = user,
                    RemainingSessionTime = remainingSessionTime,
                    LastLoginTime = lastLoginTime
                };
            }
            var lastSession = sessionHistories.OrderByDescending(e => e.UpdateDate).FirstOrDefault();
            if (lastSession != null)
            {
                lastLoginTime = lastSession.UpdateDate.ToString("G");
            }
            return new DetailModel
            {
                User = user,
                RemainingSessionTime = remainingSessionTime,
                LastLoginTime = lastLoginTime
            };

        }
    }
}
